﻿using Furion.EventBus;
using Furion.JsonSerialization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Diagnostics;
using UAParser;

namespace MyFurion.Start
{
    /// <summary>
    /// 请求日志
    /// </summary>
    public class RequestLogFilter : IAsyncActionFilter
    {
        private readonly IEventPublisher _eventPublisher;
        /// <summary>
        /// 请求日志拦截
        /// </summary>
        /// <param name="eventPublisher"></param>
        public RequestLogFilter(IEventPublisher eventPublisher)
        {
            _eventPublisher = eventPublisher;
        }
        /// <summary>
        /// 请求处理（执行操作前后）
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            var httpContext = context.HttpContext;
            var httpRequest = httpContext.Request;
            var sw = new Stopwatch();
            sw.Start();
            var actionContext = await next();
            sw.Stop();
            // 判断是否请求成功（没有异常就是请求成功）
            var isRequestSucceed = actionContext.Exception == null;
            var headers = httpRequest.Headers;
            var clientInfo = headers.ContainsKey("User-Agent") ? Parser.GetDefault().Parse(headers["User-Agent"]) : null;
            var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
            var ip = httpContext.GetRemoteIpAddressToIPv4();
            await _eventPublisher.PublishAsync(new ChannelEventSource("Add:RequestLog",
                new RequestLog
                {
                    Success=isRequestSucceed,
                    Ip = ip,
                    Location = httpRequest.GetRequestUrlAddress(),
                    Browser = clientInfo?.UA.Family + clientInfo?.UA.Major,
                    OsSystem = clientInfo?.OS.Family + clientInfo?.OS.Major,
                    Url = httpRequest.Path,
                    ClassName = context.Controller.ToString() ?? String.Empty,
                    MethodName = actionDescriptor?.ActionName ?? String.Empty,
                    ReqMethod = httpRequest.Method,
                    Param = context.ActionArguments.Count < 1 ? string.Empty : JSON.Serialize(context.ActionArguments),
                    Result = actionContext.Result?.GetType() == typeof(JsonResult) ? JSON.Serialize(actionContext.Result) : string.Empty,
                    ElapsedTime = sw.ElapsedMilliseconds
                }));
        }
    }
}
